說到自定義的 validation,大多數人通常第一時間會想到的是 validate
,
單數的、沒有 s 的 validate
,這個方法可以用來指定物件要在 validation 階段執行某些 method。
而要是專案的 form object 很多,有某些特製的 validation 很常被用到的話,通常會把他搬到抽象層,或是拉出來放在一個 module 裡面,要用再 include。
這邊介紹的是一個可以完全共用的作法,不必弄髒你的抽象層,不必額外 include module,甚至還可以回過頭讓 Active Record
也能夠共用。
那就是使用 ActiveModel::EachValidator
來製作自定義驗證。
class MyValidator < ActiveModel::EachValidator
def validate_each(form_object, attr, value)
# 您想做的驗證寫在這邊
end
def check_validity!
# 這個是 EachValidator 提供的 hook method ,會在 initialize 階段觸發
# 用來檢查其他人傳進來的 options 是否符合規則,如果不合規則,你可以 raise error
end
end
ActiveModel::EachValidator
提供了 validate_each
這個方法作為進行 validation 時統一使用的介面,並傳入三個 arguments:
- 執行 validation 的 object 本體,讓你可以在此 method 裡面往他的
errors
裡塞訊息。- 進行驗證的欄位名稱。
- 進行驗證的值。
關於 errors
的使用方式以及 i18n 規劃,之後會講XD。
這樣做有什麼好處呢?又該如何使用呢?我們先講講 validates
這個方法。
當你在 validates
後面加上 options ,假設是
validates :foo, bar: true
如果這樣設定,那 Active model
背後其實會自動去尋找 BarValidator
這個 class,並且 new 一個實體,代入此行 validation 附帶的設定,存在 class 體內。
這也就是為什麼可以整個專案都通用的原因了。
那使用方式也就很顯而易見了。像是上面定義了 MyValidator
,那我就可以這樣做:
validates :attr, my: true
這樣,ActiveModel
就會自動去使用自定義的 MyValidator
囉~
下一篇來介紹一下,假如跟著這個 key 帶入的 value 不同,有什麼應該注意的地方~